package ig.finanzas;

import ig.finanzas.riesgo.FactorRiesgoPersonal;
import ig.util.ejb.IGBean;
import ig.util.excepciones.DatoInvalidoExcepcion;
import ig.util.excepciones.LogicaExcepcion;
import java.rmi.RemoteException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.naming.NamingException;

/**
 *
 * Implementa los metodos y funciones de un contrato atomizable y que no
 * representa titulo de propiedad.
 *
 * @author lfgarcia
 */
public class PosicionEspecieBean extends ContratoBean {

    static final long serialVersionUID = 01;
    /**
     *
     * Valor nominal de la posicion.
     *
     * @uml.property name="valorNominal"
     *
     */
    private double valorNominal;
    //private double valorCompra;
    /**
     *
     * Si el contrato es Disponible para la venta o negociable.
     *
     * @uml.property name="tipo"
     *
     */
    private String tipo;
    /**
     *
     * @uml.property name="especiePK"
     *
     * @uml.associationEnd
     *
     */
    private EspeciePK especiePK;

    /**
     *
     * @return Returns the valorNominal.
     *
     * @uml.property name="valorNominal"
     *
     */
    public double getValorNominal() {
        return valorNominal;

    }

    /*
     *
     * public double getValorCompra(){
     *
     * return valorCompra;
     *
     * }
     *
     */
    /**
     *
     * Devuelve el tipo de contrato. Los valores validos son Disponible para la
     * Venta y negociables.
     *
     * @return
     *
     * @uml.property name="tipo"
     *
     */
    public String getTipo() {

        return tipo;

    }

    /**
     *
     * @return Returns the especiePK.
     *
     * @uml.property name="especiePK"
     *
     */
    public EspeciePK getEspeciePK() {

        return especiePK;

    }

    /**
     *
     * @param tipo The tipo to set.
     *
     * @uml.property name="tipo"
     *
     */
    public void setTipo(String tipo) throws DatoInvalidoExcepcion, Exception {

        if (!tipo.equals(PosicionEspecie.TIPO_DISPONIBLEVENTA) && !tipo.equals(PosicionEspecie.TIPO_NEGOCIABLE)) {
            throw new DatoInvalidoExcepcion("El tipo especificado para la posicion " + pk.getIdInterna() + " no es valido");
        }

        this.tipo = tipo;

    }

    /**
     *
     * Devuelve el precio limpio de la posicion a una fecha especifica.
     *
     * @param fecha
     *
     * @return
     *
     * @throws DatoInvalidoExcepcion Si la fecha es nula.
     *
     * @throws LogicaExcepcion Si no hay suficiente informacion para determinar
     * el valor vigente.
     *
     */
    public double getPrecioLimpio(Date fecha) throws DatoInvalidoExcepcion, LogicaExcepcion {

        return valoresRegistrados.obtenerValorVigenteA(fecha, 0);

    }

    /**
     *
     * Valora el contrato a una fecha especifica.
     *
     * @param fecha
     *
     * @return
     *
     * @throws DatoInvalidoExcepcion Si la fecha especificada es nula.
     *
     * @throws LogicaExcepcion Si la entidad no posee valores historicos
     * registrados,
     *
     * o si no se puede calcular el valor vigente de la tasa
     *
     * o si el valor calculado es imaginario.
     *
     * @throws FinderException Si no se puede encontrar la tasa de referencia
     * del periodo
     *
     * especificado.
     *
     */
    public double valorar(Date fecha)
            throws DatoInvalidoExcepcion, LogicaExcepcion, Exception {

        if (fecha == null) {
            throw new DatoInvalidoExcepcion("La fecha especificada es nula.");
        }



        if (valoresRegistrados == null) {
            throw new LogicaExcepcion("La entidad no posee valores historicos registrados.");
        }



        Date fechaultimopago = flujos.flujoAnteriorA(fecha).getFecha();

        TasaPago tasaPago = (TasaPago) tasasDePago.getRango(fecha);

        double i = tasaPago.tasaNominalPeriodo(fecha, fechaultimopago);

//		int numdiascorridos = (int)((fecha.getTime() - fechaultimopago.getTime())/(1000*60*60*24));
        int numdiascorridos = ManejadorFlujos.calcualarDias(fechaultimopago, fecha);


        //vpm = vnominal * preciolimpio + vnominal * i * diascorridos/365

        return valoresRegistrados.obtenerValorVigenteA(fecha, 0)
                + valorNominal * i * numdiascorridos / 365;

    }

    /**
     *
     * Calcula el cambio esperado de la serie de valores registrados del
     * contrato.
     *
     * @param fecha
     *
     * @param definidor
     *
     * @return
     *
     * @throws DatoInvalidoExcepcion Si alguno de los parametros recibidos es
     * invalido.
     *
     * @throws LogicaExcepcion Si la forma de calculo no permite obtener el
     * valor, si no hay suficientes
     *
     * valores en la serie, si la informacion hallada no alcanza a ser una
     * muestra estadisticamente representativa,
     *
     * o si la serie no permite el calculo utilizando diferencias logaritmicas.
     *
     */
    public double cambioEsperadoValoresRegistrados(Date fecha, DefinidorCalculoCambioEsperado definidor, boolean isPrecio) throws DatoInvalidoExcepcion, LogicaExcepcion {
        try {
            return valoresRegistrados.cambioEsperado(fecha, definidor, isPrecio);
        } catch (LogicaExcepcion e) {
            throw new LogicaExcepcion(" Posiciones Especies " + e.toString());
        }
    }

    /**
     *
     * Calcula el valor en riesgo de la posicion dependiendo de la forma como se
     * especifique
     *
     * en el factor de riesgo personal.
     *
     * @param fecha
     *
     * @param numdias
     *
     * @param factor
     *
     * @return
     *
     * @throws LogicaExcepcion Si en caso de utilizar un factor de tipo tasa el
     * contrato no tiene flujos,
     *
     * o si no se puede determinar el valor de la tasa en dicha fecha.
     *
     * @throws DatoInvalidoExcepcion Si la fecha o factor suministrado es nulo,
     * o si
     *
     * en caso de utilizar un factor de tipo tasa el valor de la tasa en esa
     * fecha es menor o igual a -1.
     *
     * Si el factor es de tipo precio y la forma de calculo no permite obtener
     * el valor, si no hay suficientes
     *
     * valores en la serie, si la informacion hallada no alcanza a ser una
     * muestra estadisticamente representativa,
     *
     * o si la serie no permite el calculo utilizando diferencias logaritmicas.
     *
     * @throws FinderException Si en caso de utilizar un factor de tipo tasa no
     * se puede cargar la tasa de descuento.
     *
     */
    public double valorEnRiesgo(Date fecha, FactorRiesgoPersonal factor, boolean isPrecio) throws DatoInvalidoExcepcion, LogicaExcepcion, Exception {
        if (fecha == null) {
            throw new DatoInvalidoExcepcion("La fecha especificada es nula.");
        }
        if (factor == null) {
            throw new DatoInvalidoExcepcion("El factor de riesgo suministrado es nulo.");
        }

        double var = 0;
        if (factor.getTipo() == FactorRiesgoPersonal.TIPO_FACTORPRECIO) {
            double cambioesperado = 0;
            if (factor.getTipoCalculoCambioEsperado() == FactorRiesgoPersonal.CAMBIOESPERADO_FACTORMATRIZ) {
                cambioesperado = factor.getFactorRiesgoMatrizCorrelacion().getCambioEsperado();
            } else {
                cambioesperado = cambioEsperadoValoresRegistrados(fecha, factor.getDefinidorCalculoCambioEsperado(), isPrecio);
            }

            var = valorNominal * cambioesperado / 100;
            //var = this.saldoContable * cambioesperado;

        } else {
            ManejadorFlujos flujosduracion = flujosParaDuracion(fecha);
            Tasa tasa = getTasa(factor.getTasaPK());

            double valorDeMercado = flujosduracion.valorDescontado(tasa, fecha, 0.0);
            double duracion = flujosduracion.duracion(fecha, tasa);
            double tir = flujosduracion.tir();
            double cambioesperado = 0;
            if (factor.getTipoCalculoCambioEsperado() == FactorRiesgoPersonal.CAMBIOESPERADO_FACTORMATRIZ) {
                cambioesperado = factor.getFactorRiesgoMatrizCorrelacion().getCambioEsperado();
            } else {
                try {
                    cambioesperado = tasa.cambioEsperadoValoresRegistrados(fecha, factor.getDefinidorCalculoCambioEsperado());
                } catch (Exception e) {
                }
            }
            var = valorDeMercado * duracion / (1 + tir) * cambioesperado;
        }
        return var;
    }

    public void eliminarEntidad() {
    }

    public void actualizarEntidad() {
    }
    private double saldoContable = 0;

    public double getSaldoContable() {
        return saldoContable;
    }

    public void setSaldoContable(double saldoContable) {
        this.saldoContable = saldoContable;
    }

    public void cargarEntidad() throws DatoInvalidoExcepcion, SQLException, Exception {
        ResultSet r1 = null;
        try {
            //ContratoPK contratoPK = (ContratoPK) ctx.getPrimaryKey();
            long idInterna = pk.getIdInterna();//contratoPK.getIdInterna();
            conn = IGBean.getMetricaDB();//getConexion("METRICADB");
            pstmt1 = conn.prepareStatement(
                    "SELECT VALORNOMINAL, P.TIPO AS TIPO, E.ISIN AS ESPECIE, IDESPECIE, "
                    + "M.NOMBRE AS MONEDA,M.ID AS IDMONEDA, C.SALDOCONTABLE "
                    + "FROM POSICIONESESPECIES P, ESPECIES E, MONEDAS M, CONTRATOS C "
                    + "WHERE P.IDESPECIE=E.ID AND E.IDMONEDA=M.ID AND C.ID=P.ID AND P.ID=? ");
            pstmt1.setLong(1, idInterna);
            r1 = pstmt1.executeQuery();
            r1.next();

            //Carga de los atributos especificos //valorregistrado
            this.valorNominal = r1.getDouble("VALORNOMINAL");

            //carga el saldo contabke 
            this.saldoContable = r1.getDouble("SALDOCONTABLE");

            //this.valorCompra = r1.getDouble("VALORCOMPRA");
            setTipo(r1.getString("TIPO"));

            this.especiePK = new EspeciePK(r1.getString("ESPECIE"));
            this.especiePK.setIdInterna(r1.getLong("IDESPECIE"));

            //Carga de los atributos generales
            this.monedaPK = new MonedaPK(r1.getString("MONEDA"));
            this.monedaPK.setIdInterna(r1.getLong("IDMONEDA"));
            try {pstmt1.close();pstmt1=null;} catch (Exception e) {}
            cargarProductoPK(idInterna);
            cargarFlujos(idInterna);
            cargarValoresRegistrados(idInterna, valorNominal);
            cargarTasasDePago(idInterna);
        } catch (SQLException e) {
            e.printStackTrace();
            throw e;
        } catch (DatoInvalidoExcepcion e) {
            e.printStackTrace();
            throw e;
        } catch (NamingException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new DatoInvalidoExcepcion(e.toString());
        } finally {
//            try {
//                conn.close();
//            } catch (Exception e) {
//            }
            try {
                pstmt1.close();
            } catch (Exception e) {
            }
            try {
                r1.close();
            } catch (Exception e) {
            }
        }
    }

    public ContratoPK ejbFindByPrimaryKey(ContratoPK pk) throws Exception {
        try {
            conn = IGBean.getMetricaDB();//getConexion("METRICADB");
            pstmt1 = conn.prepareStatement(
                    "SELECT ID "
                    + "FROM POSICIONESESPECIES "
                    + "WHERE ID=?");
            pstmt1.setLong(1, pk.getIdInterna());
            ResultSet r1 = pstmt1.executeQuery();
            if (r1.next() == false) {
                throw new Exception("No fue posible encontrar la posicion " + pk.toString());
            }

            return pk;
        } catch (Exception e) {
            throw new Exception("No fue posible cargar la posicion " + pk.toString());
        } finally {
            try {
                pstmt1.close();
            } catch (SQLException e) {
            }
//            try {
//                conn.close();
//            } catch (SQLException e) {
//            }
        }
    }

    public List ejbFindAll() throws Exception {
        ArrayList contratos = new ArrayList();
        ResultSet rs = null;
        try {
            conn = IGBean.getMetricaDB();//getConexion("METRICADB");
            pstmt1 = conn.prepareStatement("SELECT Distinct P.ID from POSICIONESESPECIES P "
                    + "INNER JOIN VALORESCONTRATOS V ON P.ID=V.IDCONTRATO "
                    + "ORDER BY P.ID");

            rs = pstmt1.executeQuery();
            while (rs.next()) {
                PosicionEspecieBean posicionEspecieBean = new PosicionEspecieBean();
                posicionEspecieBean.setPk(new ContratoPK(rs.getLong("ID")));
                //contratos.add(new ContratoPK(rs.getLong("ID")));
                posicionEspecieBean.cargarEntidad();
                contratos.add(posicionEspecieBean);
            }
        } catch (Exception e) {
            throw new Exception(e.toString());
        } finally {
            try {
                pstmt1.close();
            } catch (SQLException e) {
            }
//            try {
//                conn.close();
//            } catch (SQLException e) {
//            }
            try {
                rs.close();
            } catch (SQLException e) {
            }
        }
        return contratos;
    }
}